/**
 * 
 */
package org.mediahouse.trac.model;

/**
 * An interface definition for generic items.
 * 
 * @author Tin
 * @version %I%, %G%
 * 
 */
public interface Item {

    /**
     * Returns a textual description for this item.
     * 
     * @return this item's description; {@code null} if no description is
     *         currently defined
     */
    public String getDescription();

    /**
     * Returns the {@code ID} property of this item.
     * 
     * @return this item's {@code ID} property
     */
    public String getId();

    /**
     * Returns the value that is currently stored for the specified property
     * {@code field} of this {@code Item} instance.
     * 
     * @param field
     *            the field-name of the property for which to retrieve currently
     *            stored information
     * @return the information stored for the specified property {@code field}
     *         of this item; {@code null} if no such value is stored for the
     *         specified property
     */
    public Object getProperty(final String field);

    /**
     * Returns a {@code boolean} flag indicating whether or not this item
     * contains the specified property. In other words, this call will return
     * {@code true} if and only if there is some value (which may include
     * {@code null} depending on the implementation) stored for the specified
     * property field.
     * 
     * @param field
     *            the field-name for the property to check
     * @return {@code true} if any value is currently recorded for the specified
     *         property field; {@code false} otherwise
     */
    public boolean hasProperty(final String field);

    /**
     * Sets the provided information to the specified property for this item.
     * Always returns a reference back to this item, for convenience.
     * <p>
     * Setting a property with this method will replace whatever was previously
     * recorded for that property. Care should be taken when calling this method
     * so that properties that are implicitly final, or ones carrying important
     * information, are not overridden by accident. This can be averted by
     * always checking that the specified property contains no potentially
     * significant information before attempting to set it, using the
     * {@linkplain #hasProperty(String)} method. In cases where the item's
     * property is not modified by this call because of an illegal value or
     * illegal access, implementations may choose (but are not required) to
     * throw an {@linkplain IllegalArgumentException} to indicate that the given
     * property field was not, or should not be modified.
     * <p>
     * Thus the general pattern for the precondition variant would follow
     * something like
     * 
     * <pre>
     * <b>if</b> (<b>this</b>.hasProperty(field)) <b>throw new</b> Exception(&quot;This property already contains info!&quot;);
     * <b>else</b> setPropertyInternal(field, newInfo);
     * </pre>
     * 
     * Subclasses could use this pattern to implement immutable properties, or
     * to simply enforce explicit manipulation of properties in conjunction
     * with, for example, a {@code removeProperty(field)} method.
     * <p>
     * All implementations must clearly document the exact nature of its
     * contract, including any exceptions that may be thrown and under what
     * circumstances they will occur.
     * 
     * @param field
     *            the field-name of the property for which to store new
     *            information in this item (replacing the old information)
     * @param info
     *            the information to replace what was previously stored in the
     *            specified property field
     * @return a convenient reference to this item, for chaining
     * @throws IllegalArgumentException
     *             optionally, to indicate that the property with the specified
     *             field-name was not (or cannot be) modified
     */
    public Item setProperty(final String field, final Object info);

    /**
     * Returns the <em>Unique Identifier</em> (UID) for this item. This may or
     * may not differ from the value returned by {@link #getId()} depending on
     * the implementation.
     * <p>
     * <strong>Be aware</strong> that while the general contract of this method
     * expects the returned value to <em>uniquely</em> identify this item within
     * the context of its application, this expectation <strong>is not
     * enforced</strong> in any way by this class and should never be assumed.
     * As such it is not strictly necessary for subclasses to implement this
     * property to be truly globally unique for all its instances (i.e. it is
     * not in any way enforced by this class), and therefore the degree of
     * uniqueness <strong>cannot be guaranteed</strong> for any given
     * implementation. It is up to each implementation to externally validate
     * the UIDs of its own instances, and to clearly state the scope and extent
     * to which the uniqueness rule is enforced.
     * 
     * @return the string value used to uniquely identify this item
     */
    public String uid();
}
